package com.jr.bitcoin.address;

import com.jr.bitcoin.utils.Base58;
import com.jr.bitcoin.utils.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

//该类用于推导生成原始格式的比特币地址


public class Address {

    public static KeyPair  generateKeys(){
        //ecc椭圆曲线 , initialize初始化

        /**
         * 该方法用于生成一堆随机密钥， 并将生成的密钥对返回
         * @return 生成的密钥对对象
         */

        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            //secp256k1, secp256r1
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 该方法用于根据给定的密钥数据，推到生成对应的原始格式的比特币地址
     * @param  keyPair 生成密钥对
     * @return 推到生成的比特币地址
     */
    public String newAddress(KeyPair  keyPair){
        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
        ECPoint point = publicKey.getW();

        //原始格式的公钥
        byte[] pubKey = toUncompressePubckey(point);

//        //公钥数据进行计算
        byte[] pubKeyHash256 = Hash.SHA256(pubKey);
        byte[] pubHash = Hash.RIPEMD160(pubKeyHash256);


        byte[] version = new byte[1];
        version[0] = 0x00;//版本号

       byte[] ver_pubhash = new byte[version.length + pubHash.length];
        System.arraycopy(version,0,ver_pubhash,0,version.length);
        System.arraycopy(pubHash,0,ver_pubhash,1,pubHash.length);

        //双哈希，取前4字节
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] check = new byte[4];
        System.arraycopy(hash2,0,check,0,check.length);

        byte[] ver_pubhash_check = new byte[ver_pubhash.length + check.length];
        System.arraycopy(ver_pubhash,0,ver_pubhash_check,0,ver_pubhash.length);
        System.arraycopy(check,0,ver_pubhash_check,ver_pubhash.length,check.length);

        //对拼接到的字节组进行Base58编码
//        String addr = Base58.encode(ver_pubhash_check);
//        System.out.println(addr);


//        //原始格式公钥，压缩格式公钥
//        //原始格式公钥：04 + x坐标 + y坐标
//        byte[] xBytes = point.getAffineX().toByteArray();
//        byte[] yBytes = point.getAffineY().toByteArray();
//        System.out.println(xBytes.length);//32
//        System.out.println(yBytes.length);//32
//        //y:32   33
//              //32刚刚好，可以直接用
//               //33  0[1,32]
//        //x:32   33
//              //32   直接用
//              //33   0[1,32]

        return Base58.encode(ver_pubhash_check);
    }
    /**
     * 校验比特币地址是否符合规范，并返回校验结果
     * true符合，false不符合
     */

    public boolean validateAddr(String addr){
        if ("".equals(addr) || addr == null){
            return false;
        }
        byte[] ver_pubhash_check = Base58.decode(addr);
        if (ver_pubhash_check.length <= 4){
            return false;
        }

        byte[] check = new byte[4];
        System.arraycopy(ver_pubhash_check,ver_pubhash_check.length-4,check,0,4);

        byte[] ver_pubhash = new byte[ver_pubhash_check.length-4];
        System.arraycopy(ver_pubhash_check,0,ver_pubhash,0,ver_pubhash.length);

        //双哈希，取前4字节
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        if (hash2  == null){
            return false;
        }

        byte[] check_sum = new byte[4];
        System.arraycopy(hash2,0,check_sum,0,check_sum.length);

        //比较两个自己是否相等
        return Arrays.equals(check,check_sum);
}

    /**
     * 该方法用于生成非压缩格式的公钥数据，并返回
     * @return 非压缩格式公钥
     */


    public static byte[] toUncompressePubckey(ECPoint point){
        byte[] xBytes = point.getAffineX().toByteArray();
        byte[] yBytes = point.getAffineY().toByteArray();

        //原始格式：04 + x坐标 + y坐标 = 65字节
        byte[] pubKey = new byte[1+2*32];
        pubKey[0] = 04;
        if (xBytes.length == 32) {
            //拷贝完成数组的拼接
            System.arraycopy(xBytes, 0, pubKey, 1, xBytes.length);
            //数组的拷贝：System.arraycopy(src,start,to,to_start，length)，参数以下
            //src:拷贝的原数组
            //start:从原数组中的那个位置开始拷贝
            //to: 将数组拷贝到哪里去，
            //to_start:从目的地那个位置开始放
            //length:拷贝的长度
        }else  if (xBytes.length > 32){
            //只取后32字节
            System.arraycopy(xBytes,1,pubKey,1,32);
        }
        //y坐标
        if (yBytes.length == 32){
            System.arraycopy(yBytes,0,pubKey,33,yBytes.length);
        }else if (yBytes.length > 32){
            System.arraycopy(yBytes,1,pubKey,33,32);
        }
        return pubKey;
    }



    //该Main函数只用于临时测试时使用
//    public static void main(String[] args){
//        Address addr = new Address();
//        KeyPair keyPair = addr.generateKeys();
//        String address = addr.newAddress(keyPair);
//        boolean isValid = addr.validateAddr(address);
//        System.out.println(isValid);
//
//    }



}
